

#include "xmodule_config.h"

#if MODULE_HEARTRATE_ENABLE && PAH8009_ENABLE

#include <string.h> 

static void pah8009_send_evt(void);

#define PAH8009_NO_TOUCH_COUNT_MAX 200      //10s
#define PAH8009_TIME_OUT_COUNT_MAX 200*5    //50s

typedef struct pah8009_st
{
    uint16_t no_touch_cnt;
    uint16_t timeout_cnt;
    uint8_t no_touch;
    uint8_t timeout;
    uint8_t hr;
    uint8_t hr_grader;
    struct bp_st
    {
        uint8_t sbp;
        uint8_t dbp;
    }bp;
    uint8_t spo2;
}pah8009_t;

static pah8009_t _pah8009;

static void pah8009_reset_control(void)
{
    memset(&_pah8009,0,sizeof(_pah8009));
}

static void pah8009_set_hr(uint8_t hr , uint8_t grader)
{
    _pah8009.hr = hr;
    _pah8009.hr_grader = grader;
}

static void pah8009_set_bp(uint8_t sbp , uint8_t dbp)
{
    _pah8009.bp.sbp = sbp;
    _pah8009.bp.dbp = dbp;
}

static void pah8009_set_spo2(uint8_t spo2 )
{
    _pah8009.spo2 = spo2;
}

static void pah8009_no_touch_inc(void)
{
    _pah8009.no_touch_cnt ++;
    if(_pah8009.no_touch_cnt > PAH8009_NO_TOUCH_COUNT_MAX)
    {
        _pah8009.no_touch = 1;
    }
}

static void pah8009_no_touch_reset(void)
{
    _pah8009.no_touch_cnt = 0;
    _pah8009.no_touch = 0;
}

static void pah8009_timeout_inc(void)
{
    _pah8009.timeout_cnt ++;
    if(_pah8009.timeout_cnt > PAH8009_TIME_OUT_COUNT_MAX)
    {
        _pah8009.timeout = 1;
    }
}

#include "pah800x/sensor/pah800x_main.h"
#include "pah800x/factory/pah800x_factory_test.h"
#include "pah800x/factory/pah800x_factory_test.c"
//#include "pah800x/algorithm/pah_hr/V303009/test_library_HRD.c"
#include "pah800x/sensor/pah800x_main.c"
#include "pah800x/sensor/pah800x_bsp.c"
#include "pah800x/sensor/pah_800x.c"
#include "em_rtc.h"

static void pah8009_send_evt(void)
{
    if(NULL == m_hr_local_cb)
    {
        return;
    }
    
    if( hr_work_mode == EMHR_WORK_MODE_HEARTRATE || hr_work_mode == EMHR_WORK_MODE_DETECT)
    {
        em_heartrate_evt_t evt;
        evt.type = EM_HRS_EVT_TYPE_HEARTRATE_RESULT;
        
        if(_pah8009.no_touch)
        {
            LOG_PRINT("hr no touch");
            evt.param.HR.type = EM_HR_EVT_TYPE_NO_TOUCH;
            m_hr_local_cb( &evt );
        }
        else if(_pah8009.hr > 0 && _pah8009.hr_grader > 0)
        {
            LOG_PRINT("hr data ready");
            evt.param.HR.type = EM_HR_EVT_TYPE_READY;
            evt.param.HR.BPM = _pah8009.hr;
            m_hr_local_cb( &evt );
            _pah8009.hr = 0;
            _pah8009.hr_grader = 0;
        }
        else if(_pah8009.timeout)
        {
            LOG_PRINT("hr timeout");
            evt.param.HR.type = EM_HR_EVT_TYPE_TIMEOUT;
            m_hr_local_cb( &evt );
        }
    }
    else if( hr_work_mode == EMHR_WORK_MODE_BLOODPRESSURE )
    {
        em_heartrate_evt_t evt;
        evt.type = EM_HRS_EVT_TYPE_BP_RESULT;
        
        if(_pah8009.no_touch)
        {
            evt.param.BP.type = EM_BP_EVT_TYPE_NO_TOUCH;
            m_hr_local_cb( &evt );
        }
        else if(_pah8009.bp.sbp > 0 && _pah8009.bp.dbp > 0)
        {
            evt.param.BP.type = EM_BP_EVT_TYPE_READY;
            evt.param.BP.SBP = _pah8009.bp.sbp;
            evt.param.BP.DBP = _pah8009.bp.dbp;
            m_hr_local_cb( &evt );
            _pah8009.bp.sbp = 0;
            _pah8009.bp.dbp = 0;
        }
        else if(_pah8009.timeout)
        {
            evt.param.BP.type = EM_BP_EVT_TYPE_TIMEOUT;
            m_hr_local_cb( &evt );
        }
    }
    else if( hr_work_mode == EMHR_WORK_MODE_SPO2 )
    {
        em_heartrate_evt_t evt;
        evt.type = EM_HRS_EVT_TYPE_SPO2_RESULT;
        
        if(_pah8009.no_touch)
        {
            evt.param.SPO2.type = EM_SPO2_EVT_TYPE_NO_TOUCH;
            m_hr_local_cb( &evt );
        }
        else if(_pah8009.spo2 > 0)
        {
            evt.param.SPO2.type = EM_SPO2_EVT_TYPE_READY;
            evt.param.SPO2.realSPO2 = _pah8009.spo2;
            m_hr_local_cb( &evt );
            _pah8009.spo2 = 0;
        }
        else if(_pah8009.timeout)
        {
            evt.param.SPO2.type = EM_SPO2_EVT_TYPE_TIMEOUT;
            m_hr_local_cb( &evt );
        }
    }
    else
    {
        LOG_PRINT("send evt while invalid mode,err!!!");
    }
}

#if 1 // variable 
uint8_t stress_alg_enable = 1 ;
#endif 

#if (Test_pattern_mode==1)
//HRD
    #ifdef hrd_testpattern_en
        void test_library_HRD(void);
    #endif
//SPO2
    #ifdef spo2_testpattern_en
        void test_library_SPO2(void);
    #endif

#endif

#if 1 // function 
static
bool __pah8009_mounting(em_heartrate_desc_t* pdesc)
{
    HRS_SET_SLAVE_ADDR(PAH8009_SLAVE_ADDR_7BIT);
    
    uint8_t reg = PAH_800x_ADDR_00_PRODUCT_ID;

    for(int i = 0; i < 10; i++)
    {
        if( comm_burst_read(reg, (uint8_t *)&pdesc->chip_id, 2) == PAH_RET_SUCCESS )
        {
            LOG_PRINT("__pah8009_mounting() id = 0x%X", pdesc->chip_id );
            if( pdesc->chip_id == PAH_800x_PRODUCT_ID ) 
            {
                return true;
            }
            
        }
        HR_OS_DELAY_MS( 10 );
    }
    
    return false;
}

//static
//void __pah8009_register_callback(__pah8009_evt_handle_t cb )
//{
//    m_hr_local_cb = cb; 
//}
/**
  *
  *
  **/
void __pah8009_setup(em_heartrate_init_t* p_init_obj)
{
    (void)p_init_obj;
    
    /*============================================================================
    Test_pattern mode
    ============================================================================*/
     /* HRD*/
    #ifdef hrd_testpattern_en
        test_library_HRD();
    #endif

    /* SPO2*/
    #ifdef  spo2_testpattern_en
        test_library_SPO2();
    #endif

    /*============================================================================
    Factory_Test Function
    ============================================================================*/
    #ifdef factory_test_en
        //factory_test_mode(factory_test_brightness_golden_sample, 1, 100, 100, 40);
        //factory_test_mode(factory_test_brightness_target_sample, 1, 100, 100, 40);
        factory_test_mode(factory_test_leak_light_target_sample, 0, 0, 0, 0);
        //factory_test_mode(factory_test_power_noise, 0, 0, 0, 0);
        //factory_test_mode(factory_test_power_noise, 0, 0, 0, 0);
    #endif
    
    LOG_PRINT("__pah8009_setup()" );
    pah_sensor_init(diw_4mm_g_ir_hrd);
    auto_mode_sensor_start();
    pah_sensor_stop();
    hr_algorithm_disable();
}

static
void __pah8009_start(uint32_t mode)
{
    hr_work_mode = (em_hr_work_mode_t)mode;
    
    LOG_PRINT("__pah8009_start() mode = 0x%X", hr_work_mode );
    
    if( mode == EMHR_WORK_MODE_HEARTRATE  || mode == EMHR_WORK_MODE_DETECT)
    {
        pah8009_reset_control();
        pah_sensor_init(diw_4mm_g_ir_hrd);
        #if defined(touch_only_hrd_en)
        touch_only_sensor_start();
        #elif defined(ppg_only_hrd_en)
        ppg_only_sensor_start();
        hr_algorithm_enable();
        #elif defined(auto_hrd_en)
        auto_mode_sensor_start();
        hr_algorithm_enable();
        #endif
    }
    else if( mode == EMHR_WORK_MODE_BLOODPRESSURE )
    {
        pah8009_reset_control();
        pah_sensor_init(diw_4mm_g_ir_hrd);
        #if defined(touch_only_stress_en)
        touch_only_sensor_start();
        #elif defined(ppg_only_stress_en)
        ppg_only_sensor_start();
        stress_algorithm_enable();
        stress_alg_enable = 1 ;
        #elif defined(auto_stress_en)
        auto_mode_sensor_start();
        stress_alg_enable = 1 ;
        #endif
    }
    else if( mode == EMHR_WORK_MODE_SPO2 )
    {
        pah8009_reset_control();
        pah_sensor_init(diw_4mm_ir_r_ir_spo2);
        #if defined(touch_only_spo2_en)
        touch_only_sensor_start();
        #elif defined(ppg_only_spo2_en)
        ppg_only_sensor_start();
        spo2_algorithm_enable();
        #elif defined(auto_spo2_en)
        auto_mode_sensor_start();
        #endif
    }
    else // invalid mode, stop module 
    {
        hr_work_mode = EMHR_WORK_MODE_STOP; 
        pah_sensor_stop();
        hr_algorithm_disable();
        LOG_PRINT("stop as start mode invalid,err!!!");
        return;
    }
    
    if(hr_work_mode > EMHR_WORK_MODE_STOP && hr_work_mode <= EMHR_WORK_MODE_DETECT)
    {
        hrs_set_dlps();
    }
}

static
void __pah8009_stop(void)
{
    
    LOG_PRINT("__pah8009_stop() mode = 0x%X", hr_work_mode );
    
    if( hr_work_mode == EMHR_WORK_MODE_HEARTRATE  || hr_work_mode == EMHR_WORK_MODE_DETECT )
    {
        pah_sensor_stop();
        #if defined(touch_only_hrd_en)
        #elif defined(ppg_only_hrd_en)
        hr_algorithm_disable();
        #elif defined(auto_hrd_en)
        hr_algorithm_disable();
        #endif
    }
    else if( hr_work_mode == EMHR_WORK_MODE_BLOODPRESSURE )
    {
        pah_sensor_stop();
        #if defined(touch_only_stress_en)
        #elif defined(ppg_only_stress_en)
        stress_algorithm_disable();
        stress_alg_enable = 0 ;
        #elif defined(auto_stress_en)
        stress_alg_enable = 0 ;
        #endif
    }
    else if( hr_work_mode == EMHR_WORK_MODE_SPO2 )
    {
        pah_sensor_stop();
        #if defined(touch_only_spo2_en)
        #elif defined(ppg_only_spo2_en)
        spo2_algorithm_disable();
        #elif defined(auto_spo2_en)
        #endif
    }
    else // invalid mode, stop module 
    {
        LOG_PRINT("mode invalid while stop,err!!!");
    }
    
    hr_work_mode = EMHR_WORK_MODE_STOP;
    
    hrs_reset_dlps();
}

//static
//void __pah8009_timeout(void)
//{

//}

static
void __pah8009_process(void)
{
    
    ppg_interrupt_handle();
    ppg_sensor_task_interrupt();
    
//    LOG_PRINT("__pah8009_process() mode = 0x%X", hr_work_mode );
    if( hr_work_mode == EMHR_WORK_MODE_HEARTRATE   || hr_work_mode == EMHR_WORK_MODE_DETECT)
    {
        #if defined(touch_only_hrd_en)
        #elif defined(ppg_only_hrd_en) || defined(auto_hrd_en)
            #ifdef PPG_MEMS_Synchronize

            /**if customer want to read mems FIFO then  run PPG alg  , please call mems_interpolation()
             */
                if(mems_data_polling_ready==1)
                {
                    ppg_data_num= get_ppg_data_num();
                    mems_interpolation(ppg_data_num);
                    clear_ppg_data_num();
                    hr_alg_task2(ppg_data_num);
                }

            #else
                hr_alg_task();
            #endif
        #endif
    }
    else if( hr_work_mode == EMHR_WORK_MODE_BLOODPRESSURE )
    {
        #if defined(touch_only_stress_en)
        #elif defined(ppg_only_stress_en) || defined(auto_stress_en)
        stress_alg_task(100 );
        #endif
    }
    else if( hr_work_mode == EMHR_WORK_MODE_SPO2 )
    {
        #if defined(touch_only_spo2_en)
        #elif defined(ppg_only_spo2_en) || defined(auto_spo2_en)
            #ifdef PPG_MEMS_Synchronize

                /**if customer want to read mems FIFO then  run PPG alg  , please call mems_interpolation()
                 */
                    if(mems_data_polling_ready==1)
                    {
                        ppg_data_num= get_ppg_data_num();
                        mems_interpolation(ppg_data_num);
                        clear_ppg_data_num();
                        spo2_alg_task2(ppg_data_num);
                    }

            #else
                    spo2_alg_task();
            #endif
        #endif
    }
    else // invalid mode, stop module 
    {
        LOG_PRINT("mode invalid while process,err!!!");
    }
    
    pah8009_timeout_inc();
    
    pah8009_send_evt();
}

#endif 

const em_heartrate_instance_t HR_PAH8009 = 
{    
    .mounting = __pah8009_mounting, 
    .setup = __pah8009_setup,
    // .set_work_mode = __pah8009_set_work_mode,
    
    .start = __pah8009_start,
    .stop = __pah8009_stop,
    
    .register_callback = em_heartrate_register_callback,
    
    .timeout = __pah8009_process, 
    .process = __pah8009_process, 
};


#endif 
